package controllers

import config.{Global, MyAwait, MyFile, MyRow}
import dao.{BlockRangeDao, GenomeDao}
import play.api.data.Form
import play.api.data.Forms._

import javax.inject.Inject
import play.api.libs.json.Json
import play.api.mvc.{AbstractController, ControllerComponents}
import tools.Circos
import utils.TableUtils

import scala.concurrent.ExecutionContext

class BlockController @Inject()(blockRangeDao: BlockRangeDao, genomeDao: GenomeDao, cc: ControllerComponents)
                               (implicit exec: ExecutionContext) extends AbstractController(cc) with MyRow with MyAwait with MyFile{

  def blockPage = Action { implicit request =>
    Ok(views.html.block.blockPage())
  }

  def blockInfoPage(id: Int) = Action.async { implicit request =>
    blockRangeDao.getById(id).map { x =>
      Ok(views.html.block.blockInfoPage(x))
    }
  }

  def getBlockRangeData(species1: String, species2: String) = Action.async { implicit request =>
    blockRangeDao.getBySpecies(species1, species2).map { x =>

      val query = s"${Global.path}/blockLen/$species1.txt".readLines.map(_.split("\t").head)
      val ref = s"${Global.path}/blockLen/$species2.txt".readLines.map(_.split("\t").head)
      val xx = x.filter(y => query.contains(y.query) || query.contains(y.ref)).filter(y => ref.contains(y.query) || ref.contains(y.ref))
      val json = Json.obj("result" -> Circos.circosPlotAll(species1, species2, xx))
   //   val json = Json.obj("result" -> Circos.circosPlotAll2(  blockRangeDao.getAll.toAwait))



      Ok(Json.obj("table" -> x.map(_.getMapByT()),"circos" -> json))
    }
  }


  def plotAllSpeciesCircos = Action{implicit request=>
    Ok( Json.obj("result" -> Circos.circosPlotAll2(  blockRangeDao.getAll.toAwait)))

  }

  def getBlockInfo(id: Int) = Action.async { implicit request =>
    blockRangeDao.getById(id).map { x =>
      val genes = TableUtils.blocks(x.name)
      val ids = genes.map(g => (TableUtils.geneIdToId(g._1), TableUtils.geneIdToId(g._2)))
      val geneMap = genomeDao.getByIds(ids.flatMap(i => Seq(i._1, i._2))).toAwait.map(g => g.id -> g).toMap
      val sv = ids.map { d => (geneMap(d._1), geneMap(d._2)) }
      val data = sv.map { case (gene1, gene2) =>
        Json.obj("idA" -> gene1.id, "geneA" -> gene1.geneid, "locusA" -> s"${gene1.chr}:${gene1.start}-${gene1.end};${gene1.strand}",
          "idB" -> gene2.id, "geneB" -> gene2.geneid, "locusB" -> s"${gene2.chr}:${gene2.start}-${gene2.end};${gene2.strand}")
      }
      val rectA = sv.map(_._1).map { y => Seq(y.geneid, y.start.toString, y.end.toString) }.distinct
      val indexA =sv.map(_._1).distinct.zipWithIndex.map{y=> y._1.geneid -> (y._2+1)}.toMap
      val rectB = sv.map(_._2).map { y => Seq(y.geneid, y.start.toString, y.end.toString) }.distinct
      val indexB = sv.map(_._2).distinct.zipWithIndex.map{y=> y._1.geneid -> (y._2+1)}.toMap
      val relate = genes.map(g=> Array(indexA(g._1),indexB(g._2)))

      val row = Json.obj("A" -> Json.obj("name" -> x.query, "min" -> x.queryStart, "max" -> x.queryEnd, "rect" -> rectA),
        "B" -> Json.obj("name" -> x.ref, "min" -> x.refStart, "max" -> x.refEnd, "rect" -> rectB))
      Ok(Json.obj("data" -> row, "relate" -> relate, "table" -> data))
    }
  }


  case class SpeciesData(species1: String, species2: String)

  val SpeciesForm = Form(
    mapping(
      "species1" -> text,
      "species2" -> text
    )(SpeciesData.apply)(SpeciesData.unapply)
  )

  def getDotPlotBySpecies = Action { implicit request =>
    val form = SpeciesForm.bindFromRequest.get
    val s1 = form.species1
    val s2 = form.species2

    val files = s"${Global.path}/config/synteny".listFile.filter(x => x.getName.contains(s1) && x.getName.contains(s2))

    val name = files.head.getName.split('.').init.mkString(".")

    val na = name.split('.')
    val (xAxis, yAxis, xT, yT) = if (na.head == s1) {
      (s"${Global.path}/blockLen/$s1.txt".readLines.map(_.split("\t").head),
        s"${Global.path}/blockLen/$s2.txt".readLines.map(_.split("\t").head),
        TableUtils.genomeName(s1), TableUtils.genomeName(s2)
      )
    } else {
      (s"${Global.path}/blockLen/$s2.txt".readLines.map(_.split("\t").head),
        s"${Global.path}/blockLen/$s1.txt".readLines.map(_.split("\t").head),
        TableUtils.genomeName(s2), TableUtils.genomeName(s1)

      )
    }


    val json = files.find(_.getName.endsWith("json")).get.readFileToString
    val pos = files.find(_.getName.endsWith("pos")).get.readFileToString

    Ok(Json.obj("series" -> json, "xAxis" -> xAxis, "yAxis" -> yAxis, "pos" -> pos, "xT" -> xT, "yT" -> yT))
  }

}
